package com.mobi.Survey.map;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CancellationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.SAXException;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.location.Geocoder;
import android.location.Location;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.maps.model.LatLng;
import com.mobi.Survey.lib.R;
import com.mobi.Survey.lib.activities.LoginScreen;
import com.mobi.Survey.lib.activities.Messages;
import com.mobi.Survey.lib.activities.SurveyListScreen;
import com.mobi.Survey.lib.model.Address;
import com.mobi.Survey.lib.model.User;
import com.mobi.Survey.lib.utils.Helper;

public class MapHelper {

	public static List<Category> categories;

	public static void executeSurveyDownloadTask(final Context ctx, final MapMarker mapMarker) {
		MapSurveyDownloadTask task = new MapSurveyDownloadTask(mapMarker, ctx);
		task.setCallback(new MapSurveyDownloadTask.SurveyDownloadCallback() {

			@Override
			public void onPostExecute(int result) {
				MapHelper.onSurveyDownloadComplete(ctx, result);
			}

			@Override
			public void inBackground() {
				MapHelper.populateUserBitmaps(true);

			}
		});
		task.execute();
	}

	private static void onSurveyDownloadComplete(Context ctx, int result) {

		switch (result) {
		case MapSurveyDownloadTask.LOGIN_ERROR:
			Toast.makeText(ctx, ctx.getString(R.string.error_invalid_user_id_or_password), Toast.LENGTH_LONG).show();
			break;

		case MapSurveyDownloadTask.CONNECT_ERROR:
			Toast.makeText(ctx, ctx.getString(R.string.server_connect_error), Toast.LENGTH_LONG).show();
			break;

		case MapSurveyDownloadTask.SWITCH_SCREEN:
			MapHelper.setUserPrefrences(ctx);
			MapHelper.switchScreenTo(ctx, SurveyListScreen.class);
			break;
		case MapSurveyDownloadTask.NO_INTERNET_CONNECTION:
			Toast.makeText(ctx, Messages.NO_INTERNET_CONNECTION, Toast.LENGTH_LONG).show();
			break;

		}

	}

	public static Address findAddressUsingGoogleApi(Context ctx, Location location) {
		Address addressToShow = null;

		try {
			Geocoder gcd = new Geocoder(ctx, Locale.getDefault());
			List<android.location.Address> addresses = null;
			addresses = gcd.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
			if (addresses.size() > 0 && null != location) {
				android.location.Address geoAddress = addresses.get(0);

				Set<String> addressToken = new HashSet<String>();
				addressToShow = new Address();
				addressToShow.setStreetNumber(geoAddress.getFeatureName());
				addressToken.add(geoAddress.getFeatureName());
				if (addressToken.add(geoAddress.getThoroughfare())) {
					addressToShow.setStreetName(geoAddress.getThoroughfare());
				}

				addressToShow.setCity(geoAddress.getLocality());
				addressToken.add(geoAddress.getLocality());

				if (addressToken.add(geoAddress.getAdminArea())) {
					addressToShow.setState(geoAddress.getAdminArea());
				}
				addressToShow.setCountry(geoAddress.getCountryName());
				addressToShow.setZip(geoAddress.getPostalCode());

			}
		} catch (IOException e) {
			Log.e(MapHelper.class.getSimpleName(), "Error in getting address: " + e.getMessage());

		}

		return addressToShow;
	}

	private static JSONObject getLocationInfo(double lat, double lng) {

		HttpGet httpGet = new HttpGet("http://maps.googleapis.com/maps/api/geocode/json?latlng=" + lat + "," + lng
				+ "&sensor=true");
		HttpClient client = new DefaultHttpClient();
		HttpResponse response;
		StringBuilder stringBuilder = new StringBuilder();

		try {
			response = client.execute(httpGet);
			HttpEntity entity = response.getEntity();
			InputStream stream = entity.getContent();
			int b;
			while ((b = stream.read()) != -1) {
				stringBuilder.append((char) b);
			}
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		}

		JSONObject jsonObject = new JSONObject();
		try {
			jsonObject = new JSONObject(stringBuilder.toString());
		} catch (JSONException e) {
			e.printStackTrace();
		}

		return jsonObject;
	}

	public static Address getCurrentLocationViaJSON(double lat, double lng) {
		JSONObject jsonObj = getLocationInfo(lat, lng);

		try {
			String status = jsonObj.getString("status").toString();
			Log.i("status", status);

			if (status.equalsIgnoreCase("OK")) {
				JSONArray results = jsonObj.getJSONArray("results");

				if (results.length() > 0) {
					Address address = new Address();
					JSONObject r = results.getJSONObject(0);
					JSONArray addressComponent = r.getJSONArray("address_components");
					String value = null;

					int addressSize = addressComponent.length();
					for (int i = 0; i < addressSize; i++) {
						JSONObject addressPart = addressComponent.getJSONObject(i);
						JSONArray typesArray = addressPart.getJSONArray("types");
						String types = typesArray.getString(0);
						if ("street_number".equalsIgnoreCase(types)) {
							value = addressPart.getString("short_name");
							address.setStreetNumber(value);
						} else if ("route".equalsIgnoreCase(types)) {
							value = addressPart.getString("short_name");
							address.setStreetName(value);
						} else if ("locality".equalsIgnoreCase(types)) {
							value = addressPart.getString("short_name");
							address.setCity(value);
						} else if ("administrative_area_level_1".equalsIgnoreCase(types)) {
							value = addressPart.getString("short_name");
							address.setState(value);
						} else if ("country".equalsIgnoreCase(types)) {
							value = addressPart.getString("long_name");
							address.setCountry(value);
						} else if ("postal_code".equalsIgnoreCase(types)) {
							value = addressPart.getString("short_name");
							address.setZip(value);
						}
					}
					return address;
				}

			}

		} catch (JSONException e) {
			Log.e("testing", "Failed to load JSON");
			e.printStackTrace();
		}
		return null;
	}

	public static final void fillLangLat(Context ctx, Address address) throws IOException {

		String strAddress = address.getStreetNumber() + "," + address.getStreetName() + "," + address.getCity() + ","
				+ address.getState() + "," + address.getCountry() + "," + address.getZip();
		String mapStr = "http://maps.googleapis.com/maps/api/geocode/xml?sensor=true&address="
				+ URLEncoder.encode(strAddress);

		try {
			MapXmlParser parser = new MapXmlParser(address);
			parser.parse(mapStr);

		} catch (SAXException e) {

			e.printStackTrace();
		} catch (CancellationException e) {

		}
		Log.d(MapHelper.class.getSimpleName(), address.getCoordinates().toString());

	}

	public static final boolean isGooglePlayServicesInstalled(Activity act) {
		return new CheckGooglePlayService().servicesConnected(act);
	}

	private static double toRad(double number) {
		return number * Math.PI / 180;
	}

	private static double toDeg(double number) {
		return number * 180 / Math.PI;
	}

	public static LatLng destinationPoint(double lat, double lng, double brng, double dist) {
		final double EARTH = 6371.0;
		dist = dist / (EARTH);
		brng = toRad(brng);

		double lat1 = toRad(lat);
		double lon1 = toRad(lng);

		double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));

		double lon2 = lon1
				+ Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1),
						Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2));

		return new LatLng(toDeg(lat2), toDeg(lon2));

	}

	public static final void populateUserBitmaps(boolean downloadIfNotExist) {
		try {
			String imageUrl = User.getInstance().getListImage().getUrl();
			if (null != imageUrl && imageUrl.length() > 0) {

				String outputfile = Helper.getTempFile(Helper.getHashNameFromUrl(imageUrl) + "");
				if (!new File(outputfile).exists() && downloadIfNotExist)
					Helper.downloadFile(imageUrl, outputfile);

				User.getInstance().getListImage().setBitmap(Helper.decode(outputfile, 3));
			}

			imageUrl = User.getInstance().getDetailImage().getUrl();
			if (null != imageUrl && imageUrl.length() > 0) {

				String outputfile = Helper.getTempFile(Helper.getHashNameFromUrl(imageUrl) + "");
				if (!new File(outputfile).exists() && downloadIfNotExist)
					Helper.downloadFile(imageUrl, outputfile);

				User.getInstance().getDetailImage().setBitmap(BitmapFactory.decodeFile(outputfile));
			}
		} catch (IOException e) {
			Log.e(LoginScreen.class.getSimpleName(), "Download Error: " + e.getMessage());
		}
	}

	public static final void switchScreenTo(Context ctx, final Class<?> to) {
		final Intent intent = new Intent(ctx, to);

		ctx.startActivity(intent);
	}

	public static final void switchScreenTo(Context ctx, final Class<?> to, final Object dataToCarry) {
		final Intent intent = new Intent(ctx, to);
		if (dataToCarry instanceof Integer) {
			intent.putExtra("data", ((Integer) dataToCarry).intValue());
		}
		if (dataToCarry instanceof String) {
			intent.putExtra("data", (String) dataToCarry);
		} else if (dataToCarry instanceof Long) {
			intent.putExtra("data", (Long) dataToCarry);

		}
		ctx.startActivity(intent);
	}

	public static final void setUserPrefrences(Context ctx) {
		SharedPreferences prefs = ctx.getSharedPreferences(LoginScreen.SHARED_PREF, Context.MODE_PRIVATE);

		prefs.edit().putString(LoginScreen.KEY_LAYOUT_NAME, User.getInstance().getLayoutName())
				.putInt(LoginScreen.KEY_LAYOUT_TYPE, User.getInstance().getLayoutType())
				.putBoolean(LoginScreen.KEY_SHOW_ADS, User.getInstance().isShowAds())
				.putString(LoginScreen.KEY_LIST_IMAGE, User.getInstance().getListImage().getUrl())
				.putString(LoginScreen.KEY_DETAIL_IMAGE, User.getInstance().getDetailImage().getUrl())
				.putFloat(LoginScreen.KEY_LIST_IMAGE_SIZE, User.getInstance().getListImage().getPercentHeight())
				.putFloat(LoginScreen.KEY_DETAIL_IMAGE_SIZE, User.getInstance().getDetailImage().getPercentHeight())
				.commit();

	}

}
